package com.javacoo.swing.start;

import com.alibaba.fastjson.JSONObject;
import com.google.common.eventbus.Subscribe;
import com.javacoo.swing.api.config.TableConfig;
import com.javacoo.swing.api.monitor.MonitorWindow;
import com.javacoo.swing.core.constant.Constant;
import com.javacoo.swing.core.event.*;
import com.javacoo.xkernel.spi.ExtensionLoader;
import com.teamdev.jxbrowser.chromium.ba;
import lombok.extern.slf4j.Slf4j;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.nio.channels.FileLock;

import static javax.swing.ListSelectionModel.SINGLE_SELECTION;

/**
 * 基于jxbrowser
 * <p>
 * 说明:
 * </p>
 * <li></li>
 * 
 * @author DuanYong
 * @since 2018年10月16日上午10:02:01
 */
@Slf4j
public class StartChromeBrowser extends JFrame implements Runnable {
	private static final long serialVersionUID = 8788916259961416011L;

	/**  窗体默认宽度 */
	private static final int FRAME_DEFAULT_WIDTH = 1200;
	/** 窗体默认高度 */
	private static final int FRAME_DEFAULT_HEIGHT = 800;
	/** 系统LOGO图标 */
	private static final String SYSTEM_LOGO = "icons/logo.png";
	/** 系统title */
	private static final String TITLE = "线下支付宝扫码实时订单监控";
	/** 监控类型 */
	private static final String TYPE_TITLE = "监控类型:";
	/** 监控频率 */
	private static final String RATE_TITLE = "监控频率:";
	/** 单位 */
	private static final String SECONDS_TITLE = "秒";
	/** 商户ID */
	private static final String ACCOUNT_TITLE = "商户ID:";
	/** 启动监控 */
	private static final String START_TITLE = "启动监控";
	/** 停止监控 */
	private static final String STOP_TITLE = "停止监控";
	/** 登录支付宝 */
	private static final String LOGIN_TITLE = "登录支付宝";
	/** 显示 */
	private static final String SHOW_TITLE = "显示";
	/** 退出 */
	private static final String LOGOUT_TITLE = "退出";



	/** 文件锁路径 */
	private static String lockFile = Constant.SYSTEM_ROOT_PATH+"/lock.lock";
	/** 文件锁对象 */
	private static FileLock lock = null;
	/** 当前操作系统的托盘对象 */
	private SystemTray sysTray;
	/** 当前对象的托盘 */
	private TrayIcon trayIcon;
	/** 是否已经加载到系统托盘 */
	private boolean hasTrayIcon = false;
	/** 日志输出区域 */
	private JTextArea logOutput;
	/** 监控页面下拉 */
	private JComboBox monitorPageCbx;
	/** 随机监控时间间隔范围-最小时间 输入框 */
	private javax.swing.JTextField minField;
	/** 随机监控时间间隔范围-最大时间 输入框 */
	private javax.swing.JTextField maxField;
	/** 商户ID显示框 */
	private javax.swing.JTextField uidField;
	/** 启动监控按钮 */
	private JButton startBtn;
	/** 停止监控按钮 */
	private JButton stopBtn;
	/** 登录按钮 */
	private JButton loginBtn;
	/** Table布局配置 */
	private TableConfig tableConfig;
	/** 数据列表 */
	private DefaultTableModel model;
	/** 列表 */
	private JTable jTable;
	/** 监控类型 */
	private String monitorType="default";
	static {
		try {
			Field e = ba.class.getDeclaredField("e");
			e.setAccessible(true);
			Field f = ba.class.getDeclaredField("f");
			f.setAccessible(true);
			Field modifersField = Field.class.getDeclaredField("modifiers");
			modifersField.setAccessible(true);
			modifersField.setInt(e, e.getModifiers() & ~Modifier.FINAL);
			modifersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
			e.set(null, new BigInteger("1"));
			f.set(null, new BigInteger("1"));
			modifersField.setAccessible(false);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
	}

	public StartChromeBrowser() {
		MonitorEventBus.getInstance().register(this);
		setLayout(new BorderLayout());
		setTitle(TITLE);
		setIconImage(new ImageIcon(SYSTEM_LOGO).getImage());
		createMainPanel();
		createToolsPanel();
		setSize(FRAME_DEFAULT_WIDTH, FRAME_DEFAULT_HEIGHT);
		ininFrameConfig();
		createTrayIcon();
		setVisible(true);
	}
	/**
	 * 系统入口
	 * <p>说明:</p>
	 * <li></li>
	 * @author duanyong@jccfc.com
	 * @date 2020/6/7 14:47
	 */
	public static void main(String[] args) {
		if(!isLocking()){
			SwingUtilities.invokeLater(()->{
				try {
					UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
				} catch (Exception e) {
					e.printStackTrace();
				}
				new StartChromeBrowser();
			});
		}else {
			Toolkit.getDefaultToolkit().beep();
		}
	}
	/**
	 * 创建主界面panel
	 * <p>说明:</p>
	 * <li></li>
	 * @author duanyong@jccfc.com
	 * @date 2020/6/7 14:32
	 */
	private void createMainPanel(){
		createTablePanel();
		JPanel jPanel = new JPanel();
		jPanel.setLayout(new BoxLayout(jPanel, BoxLayout.Y_AXIS));
		jPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
		jPanel.add(new JScrollPane(jTable),BorderLayout.CENTER);
		jPanel.add(createLogPanel(),BorderLayout.SOUTH);
		this.add(jPanel, BorderLayout.CENTER);
		this.pack();
	}
	/**
	 * 创建中间显示面板
	 * <p>说明:</p>
	 * <li></li>
	 * @author duanyong@jccfc.com
	 * @date 2020/6/7 14:33
	 */
	private void createTablePanel(){
		// 创建 table
        jTable = getTable();
		// 刷新table
        refreshTable();
	}
	/**
	 * 刷新table
     * <li></li>
	 * @author duanyong@jccfc.com
	 * @date 2020/9/7 13:11
	 * @return: void
	 */
	private void refreshTable(){
        tableConfig = ExtensionLoader.getExtensionLoader(TableConfig.class).getExtension(monitorType);
        // 获取 model
        model = getTableModel();
        jTable.setModel(model);
        int[] columnWidth = tableConfig.getColumnWidths();
        for (int i = 0; i < columnWidth.length; i++) {
            // 设置表格各栏各行的尺寸
            jTable.getColumnModel().getColumn(i).setPreferredWidth(columnWidth[i]);
        }
        jTable.updateUI();
        jTable.repaint();
    }
	/**
	 * 获取一个JTable对象
	 * <p>说明:</p>
	 * <li></li>
	 * @author duanyong@jccfc.com
	 * @date 2020/6/7 14:35
	 */
	private JTable getTable() {
		JTable table = new JTable() {
			@Override
			public void updateUI() {
				// 刷新
				super.updateUI();
				// 表格行高
				setRowHeight(26);
			}
		};
		// 设置表头不可移动
		table.getTableHeader().setReorderingAllowed(false);
		// 一次只能选择一项
		table.setSelectionMode(SINGLE_SELECTION);
		return table;
	}
    /**
     * 获取默认DefaultTableModel
     * <p>说明:</p>
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2020/6/7 14:35
     */
	private DefaultTableModel getTableModel() {
		Object[][] rowData = new Object[0][tableConfig.getColumnTitles().length];
		return new DefaultTableModel(rowData, tableConfig.getColumnTitles());
	}
    /**
     * 获取当前对象的DefaultTableModel
     * <p>说明:</p>
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2020/6/7 14:36
     */
	public DefaultTableModel getModel() {
		return model;
	}
    /**
     * 设置DefaultTableModel
     * <p>说明:</p>
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2020/6/7 14:36
     */
	public void setModel(DefaultTableModel model) {
		this.model = model;
	}
    /**
     * 创建日志显示面板
     * <p>说明:</p>
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2020/6/7 14:37
     */
	private JScrollPane createLogPanel(){
		logOutput = new JTextArea();
		logOutput.setMargin(new Insets(2, 2, 2, 2));
		logOutput.setEditable(false);
		logOutput.setAutoscrolls(true);
		// 不显示滚动条
		return new JScrollPane(logOutput,
				ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
	}
	/**
	 * 常见工具栏面板
	 * <p>说明:</p>
	 * <li></li>
	 * @author duanyong@jccfc.com
	 * @date 2020/6/7 14:38
	 */
	private void createToolsPanel(){
		JPanel jPanel = new JPanel();
		jPanel.setLayout(new FlowLayout());
		jPanel.add(new JLabel(TYPE_TITLE));
		//类型
		String[] listData = new String[]{Constant.MONITOR_WINDOW_TYPE_DEFAULT, Constant.MONITOR_WINDOW_TYPE_MY_BILL};
		monitorPageCbx = new JComboBox<>(listData);
		monitorPageCbx.setSelectedIndex(0);
		// 添加条目选中状态改变的监听器
		monitorPageCbx.addItemListener(e -> {
            // 只处理选中的状态
            if (e.getStateChange() == ItemEvent.SELECTED) {
                monitorType = monitorPageCbx.getSelectedItem().toString();
                refreshTable();
            }
        });
		jPanel.add(monitorPageCbx);
		jPanel.add(new JLabel(RATE_TITLE));
		minField = new JTextField();
		minField.setColumns(5);
		minField.setText("10");
		jPanel.add(minField);
		jPanel.add(new JLabel("-"));
		maxField = new JTextField();
		maxField.setColumns(5);
		maxField.setText("20");
		jPanel.add(maxField);
		jPanel.add(new JLabel(SECONDS_TITLE));
		jPanel.add(new JLabel(" "));
		jPanel.add(new JLabel(ACCOUNT_TITLE));
		uidField = new JTextField();
		uidField.setColumns(20);
		uidField.setEnabled(false);
		jPanel.add(uidField);

		jPanel.add(new JLabel(" "));
		startBtn = new JButton(START_TITLE);
		startBtn.setEnabled(false);
		startBtn.addActionListener(e -> {
			JSONObject jsonObject = new JSONObject();
			jsonObject.put(Constant.TIMER_MIN_KEY,minField.getText());
			jsonObject.put(Constant.TIMER_MAX_KEY,maxField.getText());
			MonitorEventBus.getInstance().post(new MonitorActionEvent(ActionType.START,jsonObject));
			startBtn.setEnabled(false);
			stopBtn.setEnabled(true);
			loginBtn.setEnabled(false);
			outPutInfo("启动服务成功");
		});
		jPanel.add(startBtn);
		stopBtn = new JButton(STOP_TITLE);
		stopBtn.setEnabled(false);
		stopBtn.addActionListener(e -> {
			MonitorEventBus.getInstance().post(new MonitorActionEvent(ActionType.STOP));
			stopBtn.setEnabled(false);
			startBtn.setEnabled(true);
			outPutInfo("停止服务->成功");
		});
		jPanel.add(stopBtn);
		loginBtn = new JButton(LOGIN_TITLE);
		loginBtn.addActionListener(e -> ExtensionLoader.getExtensionLoader(MonitorWindow.class).getExtension(monitorType).start());
		jPanel.add(loginBtn);

		this.add(jPanel, BorderLayout.SOUTH);
	}
    /**
     * 打印日志
     * <p>说明:</p>
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2020/6/7 14:39
	 * @param str 日志
     */
	private void outPutInfo(String str) {
		if (logOutput.getRows() > 10) {
			logOutput.remove(10);
		}
		logOutput.append(str + ".\n");
		// 定位到控件底部
		logOutput.setCaretPosition(logOutput.getDocument().getLength());
	}


	@SuppressWarnings("resource")
	private static boolean isLocking() {
		try {
			File flagFile = new File(lockFile);
			if (!flagFile.exists()){
				flagFile.createNewFile();
			}
			lock = new FileOutputStream(lockFile).getChannel().tryLock();
			if (lock == null){
				return true;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return false;
	}
	/**
	 * 初始化主界面配置
	 * <p>说明:</p>
	 * <li></li>
	 * @author duanyong@jccfc.com
	 * @date 2020/6/7 14:40
	 */
	private void ininFrameConfig() {
		// 取得屏幕大小
		Toolkit kit = Toolkit.getDefaultToolkit();
		Dimension oursize = getSize();
		Dimension screensize = kit.getScreenSize();
		// 窗口居中显示
		int x = (screensize.width - oursize.width) / 2;
		int y = (screensize.height - oursize.height) / 2;
		x = Math.max(0, x);
		y = Math.max(0, y);
		setLocation(x, y);
		setResizable(true);
		//GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
		// 添加窗口事件
		addWindowListener(new WindowAdapter() {
			// 将托盘添加到操作系统的托盘
			@Override
			public void windowIconified(WindowEvent e) {
				addTrayIcon();
			}
		});
	}

	/**
	 * 添加托盘的方法
	 */
	private void addTrayIcon() {
		// 使得当前的窗口隐藏
		setVisible(false);
		if (!hasTrayIcon) {
			try {
				// 将托盘添加到操作系统的托盘
				sysTray.add(trayIcon);
				hasTrayIcon = true;
				new Thread(this).start();
			} catch (AWTException e1) {
				e1.printStackTrace();
			}
		}
	}

	/**
	 * 创建系统托盘的对象
	 * 步骤:
	 * 1,获得当前操作系统的托盘对象
	 * 2,创建弹出菜单popupMenu
	 * 3,创建托盘图标icon
	 * 4,创建系统的托盘对象trayIcon
	 */
	private void createTrayIcon() {
		// 获得当前操作系统的托盘对象
		sysTray = SystemTray.getSystemTray();
		// 弹出菜单
		PopupMenu popupMenu = new PopupMenu();
		MenuItem mi = new MenuItem(SHOW_TITLE);
		MenuItem exit = new MenuItem(LOGOUT_TITLE);
		popupMenu.add(mi);
		popupMenu.add(exit);
		// 为弹出菜单项添加事件
		mi.addActionListener(e -> {
			setVisible(true);
			setExtendedState(JFrame.NORMAL);
		});
		exit.addActionListener(e -> System.exit(0));
		trayIcon = new TrayIcon(new ImageIcon(SYSTEM_LOGO).getImage(), TITLE, popupMenu);
	}

	@Override
	public void run() {
		this.trayIcon.setImage(new ImageIcon(SYSTEM_LOGO).getImage());
	}

	@Override
	protected void processWindowEvent(WindowEvent e) {
		if (e.getID() == WindowEvent.WINDOW_CLOSING) {
			Toolkit.getDefaultToolkit().beep();
			int result = JOptionPane.showConfirmDialog(this, "确定退出?", "系统提示", JOptionPane.YES_NO_OPTION,
					JOptionPane.QUESTION_MESSAGE, null);
			if (result == JOptionPane.YES_OPTION) {
				this.dispose();
				System.exit(0);
			} else {
				// 直接返回，阻止默认动作，阻止窗口关闭
				return;
			}
		}
		// 该语句会执行窗口事件的默认动作(如：隐藏)
		super.processWindowEvent(e);
	}
    /**
     * 处理 DataEvent事件
     * <p>说明:</p>
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2020/6/7 14:40
     */
	@Subscribe
	public void handleDataEvent(DataEvent dataEvent){
		if(DataType.LIST_DATA == dataEvent.getDataType()){
			Object[] rowData = (Object[])dataEvent.getData().get(Constant.DATA_KEY);
			getModel().addRow(rowData);
		}else if(DataType.LOG_DATA == dataEvent.getDataType()){
			outPutInfo(String.valueOf(dataEvent.getData().get(Constant.DATA_KEY)));
		}else if(DataType.UID_DATA == dataEvent.getDataType()){
			uidField.setText(String.valueOf(dataEvent.getData().get(Constant.DATA_KEY)));
		}

	}
	/**
	 * 处理 MonitorActionEvent事件
	 * <p>说明:</p>
	 * <li></li>
	 * @author duanyong@jccfc.com
	 * @date 2020/6/7 14:41
	 */
	@Subscribe
	public void handleMonitorActionEvent(MonitorActionEvent monitorActionEvent){
		if(ActionType.LOGIN_WIN_VISIBLE == monitorActionEvent.getActionType()){
			loginBtn.setEnabled(false);
            monitorPageCbx.setEnabled(false);
		}else if(ActionType.LOGIN_WIN_HIDDEN == monitorActionEvent.getActionType()){
			loginBtn.setEnabled(true);
            monitorPageCbx.setEnabled(true);
		}else if(ActionType.DETAIL_URL_LOADED == monitorActionEvent.getActionType()){
			startBtn.setEnabled(true);
		}
	}

}
